package com.example.utils;

import com.example.MultiParamCallback;
import com.example.ParametrizedCallback;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.io.File;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.Base64;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.locks.ReentrantLock;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.crypto.spec.IvParameterSpec;
import java.nio.charset.StandardCharsets;



/**
 * 定制化工具类
 */
public class PersonalTool {

    // Redis 连接池
    private static JedisPool jedisPool;

    // 互斥锁
    private static Map<String, ReentrantLock> lockMap;
    // 排队
    private static Map<String, ReentrantLock> lockMap2;

    // 带参数的队列
    private static Map<String, ReentrantLock> lockMap3;

    //带有多个参数的队列
    private static final Map<String, ReentrantLock> lockMap4 ;

    private static final ObjectMapper objectMapper ;

    // 静态代码块初始化 JedisPool
    static {
        // 配置 JedisPool
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(10);
        poolConfig.setMinIdle(5);
        int timeout = 2000;
        String host = "localhost";
        int port = 6379;
        String pass = "X3WzfcTI3LEXPhyW";
        jedisPool = new JedisPool(poolConfig, host, port, timeout, pass);
        lockMap = new HashMap<>();
        lockMap2 = new HashMap<>();
        lockMap3 = new HashMap<>();
        lockMap4 = new HashMap<>();
        objectMapper = new ObjectMapper();
    }

    // 带有参数的队列
    public static <T> Map<String, Object> runWithLine(String key, ParametrizedCallback<T> callback, T param) {
        Map<String, Object> data = new HashMap<>();
        ReentrantLock lock = lockMap3.computeIfAbsent(key, k -> new ReentrantLock());

        while (true) {
            try {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取到锁，正在处理数据...");
                    callback.execute(param);
                    System.out.println(Thread.currentThread().getName() + " 处理数据完成，释放锁。");
                    data.put("status", "success");
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                    data.put("status", "failure");
                    break;
                } finally {
                    lock.unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
                data.put("status", "failure");
                break;
            }
        }

        return data;
    }

    public static <T> Map<String, Object> runWithLineAndParams(String key, MultiParamCallback<T> callback, T param) {
        Map<String, Object> data = new HashMap<>();
        ReentrantLock lock = lockMap4.computeIfAbsent(key, k -> new ReentrantLock());

        while (true) {
            try {
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取到锁，正在处理数据...");
                    callback.execute(param);
                    System.out.println(Thread.currentThread().getName() + " 处理数据完成，释放锁。");
                    data.put("status", "success");
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                    data.put("status", "failure");
                    break;
                } finally {
                    lock.unlock();
                }
            } catch (Exception e) {
                e.printStackTrace();
                data.put("status", "failure");
                break;
            }
        }

        return data;
    }



    /**
     * 相同业务排队顺序执行
     *
     * @param key      使用关键字区分业务，相同的 业务在同一个队列，进行排队
     * @param callback 获取到锁的请求，立即执行，没有获取到锁的请求则一直循环获取锁，直到获取到锁并执行完成
     * @return 包含执行结果的 Map
     */
    public static Map<String, Object> runWithLine(String key, Runnable callback) {
        Map<String, Object> data = new HashMap<>();
        // 获取或创建对应业务的锁
        ReentrantLock lock = lockMap2.computeIfAbsent(key, k -> new ReentrantLock());
        // 尝试获取锁，如果没有获取到则一直循环等待
        while (true) {
            try {
                //尝试添加互斥锁
                lock.lock();
                try {
                    System.out.println(Thread.currentThread().getName() + " 获取到锁，正在处理数据...");
                    // 执行回调函数
                    callback.run();
                    System.out.println(Thread.currentThread().getName() + " 处理数据完成，释放锁。");
                    data.put("status", "success");
                    break;
                } catch (Exception e) {
                    e.printStackTrace();
                    data.put("status", "failure");
                    break;
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } catch (Exception e) {
                // 这里一般不会进入，因为 lock() 方法不会抛出异常，仅为了代码结构完整
                e.printStackTrace();
                data.put("status", "failure");
                break;
            }
        }

        return data;
    }


    /**
     * 互斥锁
     *
     * @param key      使用关键字将锁分类，相同业务使用同一把锁，不同业务使用不同的锁
     * @param callback 回调函数，当抢到锁后，执行的回调函数
     * @return 是否成功获取到锁
     * @note 只有一个任务会成功
     */
    public static boolean getMutexByKey(String key, Runnable callback) {
        // 获取或创建对应业务的锁
        ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock());

        // 尝试获取锁，如果获取成功返回 true，否则返回 false
        if (lock.tryLock()) {
            try {
                System.out.println(Thread.currentThread().getName() + " 获取到锁，正在处理数据...");
                // 执行回调函数
                callback.run();
                System.out.println(Thread.currentThread().getName() + " 处理数据完成，释放锁。");
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            } finally {
                // 无论是否发生异常，都要释放锁
                lock.unlock();
            }
        } else {
            System.out.println(Thread.currentThread().getName() + " 未获取到锁，返回失败。");
            return false;
        }
    }

    // 获取 redis 缓存
    public static String getCache(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.get(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 设置 redis 缓存
    public static boolean setCache(String key, String value) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    //获取Redis
    public static Jedis getRedis() {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /* 数据库配置 */
    private static final String DB_URL = "jdbc:mysql://192.168.110.72:3306/java";
    /* 数据库用户名 */
    private static final String DB_USER = "root";
    /* 数据库密码 */
    private static final String DB_PASSWORD = "root";

    /**
     * 反转字符串
     *
     * @param input 输入的字符串
     * @return 反转后的字符串
     */
    public static String reverseString(String input) {
        if (input == null) {
            return null;
        }
        return new StringBuilder(input).reverse().toString();
    }

    /**
     * 获取当前日期，格式为 "yyyy-MM-dd"
     *
     * @return 当前日期的字符串表示
     */
    public static String getCurrentDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }

    //获取当天的日期
    public static String getCurrentDay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd");
        return sdf.format(new Date());
    }

    //获取时间戳
    public static String getTimestamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    //获取毫秒时间戳
    public static String getMilliTimeStamp() {
        return String.valueOf(System.currentTimeMillis());
    }

    //获取一个随机数
    public static int getRandomInt(int min, int max) {
        Random random = new Random();
        return random.nextInt(max - min) + min;
    }

    //获取指定长度的随机字符串
    public static String getRandomString(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(10);
            sb.append(number);
        }
        return sb.toString();
    }

    // md5加密
    public static String md5(String str) {
        try {
            // 获取 MD5 算法的 MessageDigest 实例
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 将输入的字符串转换为字节数组并进行摘要计算
            byte[] digest = md.digest(str.getBytes());
            StringBuilder sb = new StringBuilder();
            // 遍历摘要字节数组，将每个字节转换为十六进制字符串
            for (byte b : digest) {
                String hex = Integer.toHexString(b & 0xFF);
                if (hex.length() == 1) {
                    sb.append('0');
                }
                sb.append(hex);
            }
            // 返回加密后的十六进制字符串
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            // 若指定的算法（MD5）不可用，打印异常信息并返回 null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 日志目录
     */
    public static final String LOG_PATH = "webapps/log";

    //获取日志目录
    public static String getLogPath() {
        return LOG_PATH;
    }

    //文件上传目录
    public static final String UPLOAD_DIR = "webapps/uploads";

    //获取文件上传目录
    public static String getUploadDir() {
        return UPLOAD_DIR;
    }

    //获取上传路径
    public static String getUploadPath() {
        return "uploads/";
    }


    // 记录日志的方法 这里data 建议修改类型为Map<String, Object> data
    public static boolean log(int code, String msg, Map<String, String> data) {
        // 生成日志文件的完整路径，格式为 路径/日期.log
        String fileName = getLogPath() + "/" + getCurrentDay() + ".log";
        // 创建日志文件所在的目录
        File uploadDir = new File(getLogPath());
        if (!uploadDir.exists()) {
            boolean created = uploadDir.mkdirs();
            if (!created) {
                System.err.println("无法创建日志目录：" + getLogPath());
                return false;
            }
        }
        // 构建日志的具体内容
        String content = "时间：" + getCurrentDate() + " 状态码：" + code + " 消息：" + msg + " 参数：" + data.toString();
        try (FileWriter writer = new FileWriter(fileName, true)) {
            // 将日志内容写入文件，并添加换行符以分隔不同的日志条目
            writer.write(content + System.lineSeparator());
            return true;
        } catch (IOException e) {
            // 若写入过程中出现异常，打印错误信息
            System.err.println("写入日志文件时出错：" + e.getMessage());
            return false;
        }
    }

    // 获取渠道配置
    public static Map<String, Object> getChannelInformation(String sourceCode) {
        Map<String, Object> result = new HashMap<>();
        try {
            // 手动加载驱动类（可选）
            Class.forName("com.mysql.cj.jdbc.Driver");
            try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                 PreparedStatement stmt = conn.prepareStatement("SELECT * FROM promotechannel WHERE sourceCode = ? LIMIT 1")) {
                stmt.setString(1, sourceCode);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        ResultSetMetaData metaData = rs.getMetaData();
                        int columnCount = metaData.getColumnCount();
                        for (int i = 1; i <= columnCount; i++) {
                            String columnName = metaData.getColumnName(i);
                            Object columnValue = rs.getObject(i);
                            result.put(columnName, columnValue);
                        }
                    }
                }
            }
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return result;
    }


    /**
     * 检查手机号是否存在
     */
    public static boolean isPhoneExist(String phoneNumber) {
        // 首先从缓存中获取
        String cachedResult = getCache(phoneNumber);
        if (cachedResult != null) {
            return Boolean.parseBoolean(cachedResult);
        }

        try {
            // 手动加载驱动类（可选）
            Class.forName("com.mysql.cj.jdbc.Driver");
            try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                 PreparedStatement stmt = conn.prepareStatement("SELECT id FROM uclient WHERE phone = ? limit 1")) {
                stmt.setString(1, phoneNumber);
                try (ResultSet rs = stmt.executeQuery()) {
                    if (rs.next()) {
                        setCache(phoneNumber, "true");
                        return true;
                    }
                }
            }
        } catch (SQLException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        setCache(phoneNumber, "false");
        return false;
    }

    /**
     * 异常分析
     * 从这里可以分析出，所有的异常信息都是继承自 Exception
     */
    private String getFailureReason(Exception e) {
        /* 如果是 sql 异常 */
        if (e instanceof SQLException) {
            /* 强制转化类型 */
            SQLException sqlException = (SQLException) e;
            /* 获取异常码 */
            int errorCode = sqlException.getErrorCode();
            /* 状态 */
            String sqlState = sqlException.getSQLState();
            /* 消息 */
            String message = sqlException.getMessage();

            // 常见错误情况处理
            if (errorCode == 1045) { // 数据库连接认证失败
                return "Registration failed: Database authentication error.";
            } else if (errorCode == 1049) { // 数据库不存在
                return "Registration failed: Database does not exist.";
            } else if (errorCode == 1146) { // 表不存在
                return "Registration failed: Table does not exist.";
            } else if (sqlState.startsWith("23")) { // 违反约束条件，如唯一约束
                return "Registration failed: Violation of database constraints.";
            } else {
                // 未知错误，返回详细的异常信息
                return "Registration failed: " + message;
            }
        } else {
            return "Registration failed: " + e.getMessage();
        }
    }

    // 加密方法
    private static final String ALGORITHM = "AES";
    // 填充方法
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";

    /**
     * 小薇钱包解密方法
     *
     * @param input 加密后的 Base64 编码字符串
     * @param key   加密密钥
     * @return 解密后的字符串，如果解密失败返回 null
     */
    public static String xiaoWeiDecrypt(String input, String key) {
        try {
            // 将 Base64 编码的输入字符串解码为字节数组
            byte[] encryptedBytes = Base64.getDecoder().decode(input);
            // 创建 AES 密钥
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
            // 获取 Cipher 实例，指定使用 AES/ECB/PKCS5Padding 模式
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            // 初始化 Cipher 为解密模式
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            // 执行解密操作
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            // 将解密后的字节数组转换为字符串
            return new String(decryptedBytes);
        } catch (Exception e) {
            // 捕获异常并打印堆栈信息，解密失败返回 null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 小薇钱包加密方法
     *
     * @param input 待加密的字符串
     * @param key   加密密钥
     * @return 加密并进行 Base64 编码后的字符串
     */
    public static String xiaoWeiEncrypt(String input, String key) {
        try {
            // 创建 AES 密钥
            SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
            // 获取 Cipher 实例，指定使用 AES/ECB/PKCS5Padding 模式
            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
            // 初始化 Cipher 为加密模式
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            // 执行加密操作
            byte[] encryptedBytes = cipher.doFinal(input.getBytes());
            // 对加密后的字节数组进行 Base64 编码
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            // 捕获异常并打印堆栈信息，加密失败返回 null
            e.printStackTrace();
            return null;
        }
    }



    // 获取渠道信息
    public static Map<String, Object> getChannelInfo(String sourceCode) {
        // 检查渠道是否存在
        Map<String, Object> channelInfo = PersonalTool.getChannelInformation(sourceCode);
        return channelInfo;
    }

    /**
     * 获取客户端 IP 地址
     *
     * @param request HttpServletRequest 对象
     * @return 客户端 IP 地址
     */
    public static String getClientIp(HttpServletRequest request) {
        String[] headers = {
                "X-Forwarded-For",
                "X-Real-IP",
                "Client-IP",
                "X-Client-IP",
                "Via"
        };

        String ip = "";
        // 按优先级从请求头中获取 IP 地址
        for (String header : headers) {
            String headerValue = request.getHeader(header);
            if (headerValue != null && !headerValue.isEmpty()) {
                String[] ips = headerValue.split(",");
                ip = ips[0].trim();
                break;
            }
        }

        // 如果从请求头中未获取到 IP 地址，则从 REMOTE_ADDR 获取
        if (ip.isEmpty()) {
            ip = request.getRemoteAddr();
        }

        return ip;
    }

    // 定义为静态成员变量
    private static final Map<Integer, String> fields = new HashMap<>();

    //这么写的作用是只赋值一次，防止反复赋值实例化map，降低内存开销，提升运行效率
    static {
        // 在静态代码块中初始化
        fields.put(0, "zero");
        fields.put(1, "one");
        fields.put(2, "two");
        fields.put(3, "three");
        fields.put(4, "four");
        fields.put(5, "five");
    }

    /**
     * 通过星级获取公海撞库配置字段
     *
     * @param star 星级
     * @return 对应的配置字段
     * @note 这个是模拟的php的isset
     */
    public static String getLevelByStar(int star) {
        return fields.getOrDefault(star, "zero");
    }

    //base64解码
    public static String base64decode(String encodedData) {
        byte[] decodedBytes =   org.apache.commons.codec.binary.Base64.decodeBase64(encodedData);
        // 进行 Base64 解码 这是第二种方法
        //byte[] decodedBytes = Base64.getDecoder().decode(encodedData);
        // 将解码后的字节数组转换为字符串
        String decodedData = new String(decodedBytes);
        return decodedData;

    }

    //base64编码
    public static String base64encode(String originalData) {
        // 进行 Base64 编码
        //return Base64.getEncoder().encodeToString(originalData.getBytes());
        return org.apache.commons.codec.binary.Base64.encodeBase64String(originalData.getBytes());
    }

    // json编码
    public static String json_encode(Map<String, Object> originData) {
        try {
            // 将 Map 对象转换为 JSON 字符串
            return objectMapper.writeValueAsString(originData);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    // json 解码
    public static Map<String, Object> json_decode(String jsonData) {
        try {
            // 将 JSON 字符串转换为 Map 对象
            return objectMapper.readValue(jsonData, HashMap.class);
        } catch (Exception e) {
            e.printStackTrace();
            return new HashMap<>();
        }
    }


    /**
     * rsa使用公钥加密
     *
     * @param publicKey 公钥,没有被加工分割过的base64字符串
     * @param data      待加密的字符串
     * @return 加密后的字符串
     */
    public static String rsaEncodeByPublicKey(String publicKey, String data) {
        try {
            return RSA.encryptByPublicKey(publicKey, data);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * rsa使用私钥解密
     *
     * @param privateKey 私钥，没有被加工分割过的base64字符串
     * @param data       待解密的字符串
     * @return 解密后的字符串
     */
    public static String rsaDecodeByPrivateKey(String privateKey, String data) throws Exception {
       try{
           return RSA.decryptByPrivateKey(privateKey, data);
       } catch (Exception e) {
           e.printStackTrace();
           return "";
       }
    }

    /**
     * 私钥加密
     * @param privateKey 私钥 base64加密后的私钥，没有被加工分割过的字符串
     * @param data 待加密的字符串
     * @return
     * @throws Exception
     */
    public static String rsaEncodeByPrivateKey(String privateKey, String data) throws Exception {
        try{
            return RSA.encryptByPrivateKey(privateKey, data);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 公钥解密
     * @param publicKey 公钥 被base64加密后的公钥，没有被加工分割过的字符串
     * @param data 待解密的字符串
     * @return
     * @throws Exception
     */
    public static String rsaDecodeByPublicKey(String publicKey, String data) throws Exception {
        try{
            return RSA.decryptByPublicKey(publicKey, data);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }


    /** 下面是aes加密和解密的配置 */
    public static final String AES_ALGORITHM = "AES";
    public static final String ECB_MODE = "ECB"; // easy 就是简单模式，不需要向量
    public static final String CBC_MODE = "CBC"; // 复杂模式，需要向量
    public static final String AES_PADDING = "PKCS5Padding";
    public static final String DEFAULT_IV = "0000000000000000";

    // 加密方法，iv 可选
    public static String aesEncode(String input, String key, String mode) {
        return aesEncode(input, key, mode, "");
    }

    // aes加密 方法重载 ，java可以存在名称相同的方法，java是依照名称+参数 来区分不同的方法的
    public static String aesEncode(String input, String key, String mode, String iv) {
        try {
            // 确保密钥长度符合 AES 要求
            validateKeyLength(key);
            // 加载aes秘钥
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
            // 拼装加密模式
            String transformation = AES_ALGORITHM + "/" + mode + "/" + AES_PADDING;
            // 加载加密器
            Cipher cipher = Cipher.getInstance(transformation);
            // cbc 如果是高级加密模式
            if (mode.equals(CBC_MODE)) {
                // 初始化向量
                IvParameterSpec ivParameterSpec;
                if (iv == null || iv.isEmpty()) {
                    // 如果向量为空，则使用默认值向量
                    ivParameterSpec = new IvParameterSpec(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
                } else {
                    // 否则，向量去iv的字节
                    ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
                }
                // 加密器初始化，加载key 和 iv
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
            } else {
                // ecb简单模式
                cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
            }
            // 传入待加密数据，获取加密后的结果
            byte[] encryptedBytes = cipher.doFinal(input.getBytes(StandardCharsets.UTF_8));
            // 因为加密后的数据是二进制，需要转化为字节，使用base64加密
            return Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 解密方法，iv 可选
    public static String aesDecode(String input, String key, String mode) {
        return aesDecode(input, key, mode, "");
    }

    // aes 方法重载
    public static String aesDecode(String input, String key, String mode, String iv) {
        try {
            // 确保密钥长度符合 AES 要求
            validateKeyLength(key);
            // 加载秘钥
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), AES_ALGORITHM);
            // 拼装加密模式
            String transformation = AES_ALGORITHM + "/" + mode + "/" + AES_PADDING;
            // 获取加密实例
            Cipher cipher = Cipher.getInstance(transformation);
            // cbc高级模式
            if (mode.equals(CBC_MODE)) {
                IvParameterSpec ivParameterSpec;
                if (iv == null || iv.isEmpty()) {
                    ivParameterSpec = new IvParameterSpec(DEFAULT_IV.getBytes(StandardCharsets.UTF_8));
                } else {
                    ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
                }
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
            } else {
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            }

            byte[] decodedBytes = Base64.getDecoder().decode(input);
            byte[] decryptedBytes = cipher.doFinal(decodedBytes);
            return new String(decryptedBytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 验证key秘钥的长度
    private static void validateKeyLength(String key) {
        int validKeyLengths[] = {16, 24, 32};
        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
        boolean isValid = false;
        for (int length : validKeyLengths) {
            if (keyBytes.length == length) {
                isValid = true;
                break;
            }
        }
        if (!isValid) {
            throw new IllegalArgumentException("AES 密钥长度必须为 16、24 或 32 字节");
        }
    }


    /**
     * 通用数据库查询方法
     * @param sql sql 语句
     * @param params 参数集合
     * @return 结果集 执行成功： ["status"=>200,"message"=>"success","data"=>[查询结果,增删改条数]] 执行失败： ["status"=>400,"message"=>"错误原因","data"=>[]]
     */
    public static Map<String, Object> queryDataFromMysql(String sql, Map<String, Object> params) {
        // 初始化结果集
        Map<String, Object> back = new HashMap<>();
        back.put("status", 200);
        back.put("message", "success");
        back.put("data", new ArrayList<>());
        back.put("rows", 0);

        // 用于存储查询结果的数据
        List<Map<String, Object>> resultList = new ArrayList<>();
        // 操作状态，默认失败
        boolean success = false;
        // 错误信息
        String errorMessage = null;

        try {
            // 手动加载驱动类（可选）
            Class.forName("com.mysql.cj.jdbc.Driver");
            try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                 // 创建 PreparedStatement 对象
                 PreparedStatement stmt = conn.prepareStatement(sql)) {
                // 给 sql 绑定参数
                int index = 1;
                for (Map.Entry<String, Object> entry : params.entrySet()) {
                    Object value = entry.getValue();
                    if (value instanceof Integer) {
                        stmt.setInt(index++, (Integer) value);
                    } else if (value instanceof Double) {
                        stmt.setDouble(index++, (Double) value);
                    } else if (value instanceof String) {
                        stmt.setString(index++, (String) value);
                    } else {
                        // 可以根据需要添加更多类型的处理
                        stmt.setObject(index++, value);
                    }
                }

                // 判断 SQL 类型，根据不同类型执行不同操作
                if (sql.trim().toLowerCase().startsWith("select")) {
                    // 执行查询操作
                    try (ResultSet rs = stmt.executeQuery()) {
                        ResultSetMetaData metaData = rs.getMetaData();
                        int columnCount = metaData.getColumnCount();
                        while (rs.next()) {
                            Map<String, Object> row = new HashMap<>();
                            for (int i = 1; i <= columnCount; i++) {
                                row.put(metaData.getColumnName(i), rs.getObject(i));
                            }
                            resultList.add(row);
                        }
                        success = true;
                    }
                } else {
                    // 执行增删改操作
                    int rowsAffected = stmt.executeUpdate();
                    back.put("rows", rowsAffected);
                    success = rowsAffected > 0;
                }
            }
        } catch (SQLException | ClassNotFoundException e) {
            errorMessage = e.getMessage();
            e.printStackTrace();
        }

        // 将操作状态、错误信息和查询结果添加到返回结果中
        back.put("status", success?200:400);
        if (errorMessage != null) {
            back.put("message", errorMessage);
        }
        if (!resultList.isEmpty()) {
            back.put("data", resultList);
        }

        // 返回结果集
        return back;
    }

    //返回响应
    public static String response(Map<String,Object> data,int code,String message){
        Map<String,Object> back = new HashMap<>();
        back.put("status", code);
        back.put("message", message);
        back.put("data", data);
        return json_encode(back);
    }

    //快速响应
    public static String response(Map<String,Object> data){
        return response(data,200,"success");
    }
}